#include "gtest/gtest.h"
#include <acapella/delegate/functor.hpp>

using namespace acapella::delegate;

int FunctionAdd(int a, int b)
{
	return a + b;
}

class A
{
public:
	virtual ~A(){}

	virtual int change(int a, int b){return a + b;}
	virtual A*  copy(const A&){return new A();}
protected:
	int i;
};

class B : public A
{
public:
	virtual int change(int a, int b){return a - b;}
	virtual A*  copy(const A&){return new B();};
};


TEST(FunctorTest, NormalFunctionTest)
{
	functor<int(int,int), dynamic_bind> dynamic_func_add(&FunctionAdd);
	EXPECT_EQ(2, dynamic_func_add(1, 1));
	functor<int(int,int), static_bind> static_func_add(&FunctionAdd);
	EXPECT_EQ(2, static_func_add(1, 1));
}

TEST(FunctorTest, ClassFunctionTest)
{
	A* p = new B;

	functor<int(int,int), dynamic_bind> dynamic_func_add(p, &A::change);
	EXPECT_EQ(0, dynamic_func_add(1, 1));
	functor<int(int,int), static_bind, A> static_func_add(p, &A::change);
	EXPECT_EQ(0, static_func_add(1, 1));

	delete p;
}

TEST(FunctorTest, DynamicSharedPointerTest)
{
	acapella::shared_ptr<A> p(new B);

	functor<int(int,int), dynamic_bind> dynamic_func_add(p, &A::change);
	EXPECT_EQ(0, dynamic_func_add(1, 1));
}

TEST(FunctorTest, DynamicClassFunctionTest)
{
	A* p = new B;

	functor<A*(const A&), dynamic_bind> dynamic_func_add(p, &A::copy);
	EXPECT_NE(p, dynamic_func_add(*p));

	delete p;
}

TEST(FunctorTest, StaticClassFunctionTest)
{
	A* p = new B;

	functor<A*(const A&), static_bind, A> static_func_add(p, &A::copy);
	EXPECT_NE(p, static_func_add(*p));

	delete p;
}

TEST(FunctorTest, DynamicPerformanceTest)
{
	functor<int(int,int), dynamic_bind> dynamic_func_add(&FunctionAdd);
	int i = 1000000;
	int sum = 0;
	while (i--)
	{
		sum += dynamic_func_add(1, 1);
	}

	EXPECT_NE(0, sum);
}

TEST(FunctorTest, StaticPerformanceTest)
{
	functor<int(int,int), static_bind> dynamic_func_add(&FunctionAdd);
	int i = 1000000;
	int sum = 0;
	while (i--)
	{
		sum += dynamic_func_add(1, 1);
	}

	EXPECT_NE(0, sum);
}

TEST(FunctorTest, BenchTestTest)
{
	int i = 1000000;
	int sum = 0;
	while (i--)
	{
		sum += FunctionAdd(1, 1);
	}

	EXPECT_NE(0, sum);
}


TEST(FunctorListTest, DynamicFunctionTest)
{
	A* p = new B;

	functor_list<int(int,int), dynamic_bind> dynamic_func_list_add(&FunctionAdd);
	dynamic_func_list_add += functor_list<int(int,int), dynamic_bind>::functor_type(&FunctionAdd);
	dynamic_func_list_add += functor_list<int(int,int), dynamic_bind>::functor_type(p, &A::change);
	EXPECT_EQ(0, dynamic_func_list_add(1, 1));

	delete p;
}

TEST(FunctorListTest, StaticNormalFunctionTest)
{
	functor_list<int(int,int), static_bind> dynamic_func_list_add(&FunctionAdd);
	dynamic_func_list_add += functor_list<int(int,int), static_bind>::functor_type(&FunctionAdd);
	EXPECT_EQ(2, dynamic_func_list_add(1, 1));
}

TEST(FunctorListTest, StaticClassFunctionTest)
{
	A* p = new B;

	functor_list<int(int,int), static_bind, A> dynamic_func_list_add(
		functor_list<int(int,int), static_bind, A>::functor_type(p, &A::change));
	dynamic_func_list_add += functor_list<int(int,int), static_bind, A>::functor_type(p, &A::change);
	EXPECT_EQ(0, dynamic_func_list_add(1, 1));

	delete p;
}








